use std::fmt::Debug;

use common_base::prelude::*;
use common_core::{data::Metadata, ServiceContext, ServiceContextBase};

use crate::model::MdmDataModel;

#[derive(Debug)]
pub struct MDMContext {
    pub(crate) service_context_base: ServiceContextBase,
    pub(crate) biz_metadata: Option<Metadata>,
    pub(crate) dct_metadata: Option<Metadata>,
}

impl MDMContext {
    pub fn get_instance(service_context_base: ServiceContextBase) -> Self {
        Self {
            service_context_base,
            biz_metadata: None,
            dct_metadata: None,
        }
    }

    #[inline]
    pub fn downcast_from(srv_ctx: &dyn ServiceContext) -> Result<&MDMContext> {
        srv_ctx
            .as_any()
            .downcast_ref::<MDMContext>()
            .ok_or(ErrorCode::PluginParamTypeInvalid(
                "expect MDMContext but not.",
            ))
    }

    #[inline]
    pub fn downcast_from_mut(srv_ctx: &mut dyn ServiceContext) -> Result<&mut MDMContext> {
        srv_ctx
            .as_any_mut()
            .downcast_mut::<MDMContext>()
            .ok_or(ErrorCode::PluginParamTypeInvalid(
                "expect MDMContext but not.",
            ))
    }

    pub fn get_response_payload_mut(&mut self) -> Result<&mut MdmDataModel> {
        self.get_response_object_mut()
            .get_payload_mut()
            .map(|p| {
                p.as_any_mut()
                    .downcast_mut::<MdmDataModel>()
                    .expect("response payload downcast to MdmDataModel failed")
            })
            .ok_or(ErrorCode::UnImplement("response payload must not be none."))
    }
}

impl ServiceContext for MDMContext {
    fn get_service_context_base(&self) -> &ServiceContextBase {
        &self.service_context_base
    }
    fn get_service_context_base_mut(&mut self) -> &mut ServiceContextBase {
        &mut self.service_context_base
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
        self
    }
}
